package assignmentstrategy

import (
	"codejy/analysis"
	"codejy/analysis/codeanalysis"
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"codejy/utils"
	"math"
	"strconv"
	"strings"
)

type NewInstanceStrategy struct {
}

func init() {
	RegisterStrategy(&NewInstanceStrategy{})
	globalfunc.RegisterFuncAll("ExecuteTypeMethod", ExecuteTypeMethod)
	globalfunc.RegisterFuncAll("InitProperties", InitProperties)
}
func (n NewInstanceStrategy) getId() int {
	return codeanalysis.NewInstance
}

func (n NewInstanceStrategy) Execute(threadStore *structdef.ThreadStore, code string) string {
	instanceId := CreateInstance(threadStore, code) //创建实例
	return instanceId
}

// 创建实例,返回实例地址
func CreateInstance(threadStore *structdef.ThreadStore, expression string) string {
	//截取new()中的内容
	lineCode := expression[strings.Index(expression, "new(")+4 : strings.LastIndex(expression, ")")]
	//将字符串替换为占位符
	replace, str := utils.StrReplace(lineCode)
	//以逗号分割
	split := strings.Split(str, ",")
	//获取类型名
	typeName := replace[split[0]]
	//将类型名称字符串去掉"
	typeName = strings.Replace(typeName, "\"", "", -1)
	//判断是否是其他文件的类型,  获取第一个点位置
	index := strings.Index(typeName, ".")
	handleFilePath := threadStore.HandleFilePath
	if index != -1 {
		//截取第一个.之前的字符串
		fileName := typeName[:index]
		fileName = store.GetImportFile(fileName, handleFilePath)
		handleFilePath = typeName[index+1:]
	}
	//获取类型参数
	var split1 = split[1:]
	//还原内容
	for k, v := range split1 {
		restore := utils.StrRestore(v, replace)
		split1[k] = restore
	}
	typeParams := split1
	//拿到类型定义
	typeDefinition := store.GetTypeDefinition(handleFilePath, typeName)
	if typeDefinition == nil {
		panic("类型未定义:" + typeName)
	}
	//判断是否是共享类型
	if typeDefinition.IsShare {
		panic("共享类型不能实例化:" + typeName)
	}

	addr := utils.InstantiateAddressGeneratoSafe() //生成实例地址

	//初始化属性
	properties := InitProperties(threadStore, typeName, typeDefinition.Properties, typeParams, handleFilePath)
	//注册实例变量
	store.RegisterInstance(threadStore, addr, properties)

	store.NweStatusRestore(threadStore, func() string {
		threadStore.CurrentInstanceAddress = addr
		//执行所有父,初始化init方法
		for i := 0; i < math.MaxInt; i++ {
			definition, p := typeDefinition.Methods["init"+"_"+strconv.Itoa(i)]
			if p {
				ExecuteTypeMethod(threadStore, "init", definition, typeParams)
			} else { //父类型中没有init方法
				break
			}
		}
		//执行当前init方法
		definition, p := typeDefinition.Methods["init"]
		if p {
			ExecuteTypeMethod(threadStore, "init", definition, typeParams)
		}
		return ""
	})
	return addr
}

// 初始化属性
func InitProperties(threadStore *structdef.ThreadStore, typeName string, properties []structdef.PropertiesDefinition, parameter []string, filePath string) map[string]structdef.VarDefinition {
	var mapParams = make(map[string]structdef.VarDefinition)
	//给properties属性赋值为默认值
	if properties != nil {
		for i := range properties {
			fieldName := properties[i].Name
			//参数值
			paramValue := ""
			//获取新的参数类型
			paramType := globalfunc.ExecuteFunc("CodeAnalysis", threadStore, paramValue).(int)
			//注册参数
			mapParams[fieldName] = structdef.NewVarDefinitionValue(fieldName, paramValue, paramType)
		}
	}
	//添加实例类型名称,用于之后方法调用,或者类型判断等
	mapParams["@TYPENAME@"] = structdef.NewVarDefinitionValue(typeName, typeName, -1)
	//类型定义所在文件
	mapParams["@TYPEFILEPATH@"] = structdef.NewVarDefinitionValue(filePath, filePath, -1)
	if len(parameter) > 0 {
		var NameParams = false
		//判断是否存在命名参数
		for i := range parameter {
			if strings.HasPrefix(parameter[i], "$") {
				NameParams = true
				break
			}
		}
		if NameParams {
			for i := range properties {
				for j := range parameter {
					//参数值
					paramValue := parameter[j]
					//获取=号左边的变量
					varName := paramValue[:strings.Index(paramValue, "=")]
					varName = varName[1:]
					if properties[i].Name != varName {
						continue
					}
					//获取=号右边的表达式
					expression := paramValue[strings.Index(paramValue, "=")+1:]
					//解析参数
					transition := globalfunc.ExecuteFunc("DefaultParamTransition", threadStore, []string{expression}).([]string)
					//参数类型
					paramType := globalfunc.ExecuteFunc("CodeAnalysis", threadStore, paramValue).(int)
					mapParams[varName] = structdef.NewVarDefinitionValue(varName, transition[0], paramType)
				}
			}

		} else {
			//解析参数
			transition := globalfunc.ExecuteFunc("DefaultParamTransition", threadStore, parameter).([]string)
			for i := range properties {
				fieldName := properties[i].Name
				//参数值
				paramValue := transition[i]
				//获取新的参数类型
				paramType := globalfunc.ExecuteFunc("CodeAnalysis", threadStore, paramValue).(int)
				//注册参数
				mapParams[fieldName] = structdef.NewVarDefinitionValue(fieldName, paramValue, paramType)
			}
		}
	}
	return mapParams
}

// 执行实例方法
func ExecuteTypeMethod(threadStore *structdef.ThreadStore, funcName string, behaviorDefinition structdef.BehaviorDefinition, funParams []string) {
	utils.CodeExecutionTime("实例方法耗时情况", threadStore, func() {
		//实例执行的时候会切换到实例的作用域，那么参数解析的时候是需要在之前的作用域解析的，所以需要先解析参数，然后再切换到实例作用域进行方法执行
		funParams = globalfunc.ExecuteFunc("DefaultParamTransition", threadStore, funParams).([]string)
		store.FuncStatusRestore(threadStore, func(parentEnv string, parentCodes []structdef.LineCodeDefinition, parentCode structdef.LineCodeDefinition) {
			//设置当前作用域,为类型函数名称
			store.AddCurrentEnv(threadStore, funcName)
			store.AddParentEnv(threadStore, parentEnv)
			//拿到函数体
			body := behaviorDefinition.Body
			globalfunc.ExecuteFunc("FunLineExecute", threadStore, body, parentEnv, behaviorDefinition.BehaviorName, funParams)
			//清除当前作用函数域的所有变量
			currentenv := threadStore.CurrentEnv
			store.DeleteVariableScope(threadStore, currentenv)
		})
	})
}

// 创建实例,不会执行init方法
func CreateInstanceMapNotInit(threadStore *structdef.ThreadStore, typeName string, parameter map[string]string) string {
	index := strings.Index(typeName, ".")
	handleFilePath := threadStore.HandleFilePath
	if index != -1 {
		//截取第一个.之前的字符串
		fileName := typeName[:index]
		fileName = store.GetImportFile(fileName, handleFilePath)
		handleFilePath = typeName[index+1:]
	}
	//拿到类型定义
	typeDefinition := store.GetTypeDefinition(handleFilePath, typeName)
	if typeDefinition == nil {
		panic("类型未定义:" + typeName)
	}
	//判断是否是共享类型
	if typeDefinition.IsShare {
		panic("共享类型不能实例化:" + typeName)
	}
	addr := utils.InstantiateAddressGeneratoSafe() //生成实例地址
	var mapParams = make(map[string]structdef.VarDefinition)
	//添加实例类型名称,用于之后方法调用,或者类型判断等
	mapParams["@TYPENAME@"] = structdef.NewVarDefinitionValue(typeName, typeName, -1)
	//类型定义所在文件
	mapParams["@TYPEFILEPATH@"] = structdef.NewVarDefinitionValue(handleFilePath, handleFilePath, -1)
	for i := range typeDefinition.Properties {
		fieldName := typeDefinition.Properties[i].Name
		v, p := parameter[fieldName]
		if p {
			marks := analysis.AddDoubleQuotationMarks(v) //给字符串添加双引号
			paramType := globalfunc.ExecuteFunc("CodeAnalysis", threadStore, marks).(int)
			mapParams[fieldName] = structdef.NewVarDefinitionValue(fieldName, v, paramType)
		} else {
			mapParams[fieldName] = structdef.NewVarDefinitionValue(fieldName, "", -1)
		}
	}
	//注册实例变量
	store.RegisterInstance(threadStore, addr, mapParams)
	return addr
}

// 创建实例,不需要实际存在的类型,完全通过参数来创建实例
func CreateInstanceMapNotInitByParams(threadStore *structdef.ThreadStore, typeName string, parameter map[string]string) string {
	handleFilePath := threadStore.HandleFilePath
	addr := utils.InstantiateAddressGeneratoSafe() //生成实例地址
	var mapParams = make(map[string]structdef.VarDefinition)
	//添加实例类型名称,用于之后方法调用,或者类型判断等
	mapParams["@TYPENAME@"] = structdef.NewVarDefinitionValue(typeName, typeName, -1)
	//类型定义所在文件
	mapParams["@TYPEFILEPATH@"] = structdef.NewVarDefinitionValue(handleFilePath, handleFilePath, -1)
	for k, v1 := range parameter {
		marks := analysis.AddDoubleQuotationMarks(v1) //给字符串添加双引号
		paramType := globalfunc.ExecuteFunc("CodeAnalysis", threadStore, marks).(int)
		mapParams[k] = structdef.NewVarDefinitionValue(k, v1, paramType)
	}
	//注册实例变量
	store.RegisterInstance(threadStore, addr, mapParams)
	return addr
}
